package com.monkey.service;

import com.monkey.core.ErrorCode;
import com.monkey.generator.dao.TMonkeyCreateMapper;
import com.monkey.generator.dao.TUserLuckMapper;
import com.monkey.generator.model.TMonkeyCreate;
import com.monkey.generator.model.TUserLuck;
import com.monkey.generator.model.TUserLuckExample;
import com.monkey.model.luck.LuckData;
import com.monkey.model.monkey.Monkey;
import com.monkey.model.monkey.MonkeyCreate;
import com.monkey.model.monkey.MonkeySpecify;
import com.monkey.model.user.User;
import com.monkey.util.DateUtil;
import com.monkey.util.WebConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static com.monkey.service.MonkeyService.MONKEY_FROM_LUCK;
import static com.monkey.service.MonkeyService.MONKEY_STATUS_NORMAL;
import static com.monkey.service.UserService.ACTION_LUCK;

/**
 * desc:
 * auth: chenxiaobin
 * data: 2018/2/3.
 */
@Service
@Transactional
public class LuckService {
    private static Logger logger = LoggerFactory.getLogger(LuckService.class);
    private List<Item> items = new ArrayList<>();
    private int range = 0;
    private int nohit = 0;

    @Resource
    private UserService userService = null;

    @Resource
    private MonkeyService monkeyService = null;

    @Resource
    private TMonkeyCreateMapper monkeyCreateMapper = null;

    @Resource
    private TUserLuckMapper userLuckMapper = null;

    @Resource
    private DateUtil dateUtil = null;

    @Resource
    private WebConfig webConfig = null;

    public void init() {
        String weights = webConfig.get("luck.weights");
        String[] list = weights.split("\\|");
        int size = list.length;
        int pos = 0;
        for (int i = 0; i < size; ++i) {
            int n = Integer.valueOf(list[i]);
            if (n > 0) {
                List<Integer> p1 = new ArrayList<>();
                List<Integer> p2 = new ArrayList<>();
                String reward = webConfig.get("luck.item" + i);
                String[] rewards = reward.split("\\|");
                int generation = Integer.valueOf(rewards[0]);
                String value = rewards[1];
                String[] values = value.split(",");
                for (String uuid : values) {
                    String[] uuids = uuid.split("-");
                    p1.add(Integer.valueOf(uuids[0]));
                    p2.add(Integer.valueOf(uuids[1]));
                }
                items.add(new Item(pos, pos + n, generation, p1, p2));
                pos = pos + n + 1;
                range = pos;
            }
        }
        nohit = webConfig.getInt("luck.nohit");
    }

    public LuckData doLuck(User user, int price) {
        int price1 = webConfig.getInt("luck.money");
        if (price != price1) {
            return new LuckData(ErrorCode.PARAM_ERROR);
        }

        SimpleDateFormat sdf = dateUtil.getSimpleDateFormat();
        Date now = new Date();
        String dateString = sdf.format(now);

        // 钱不够扣
        if (user.getMoney().floatValue() < price) {
            return new LuckData(ErrorCode.WALLET_LESS_ERROR);
        }

        // 限次数
        TUserLuckExample example = new TUserLuckExample();
        example.or().andUseridEqualTo(user.getId()).andCreatetimeEqualTo(dateString);
        example.setLimit(1);
        List<TUserLuck> list = userLuckMapper.selectByExample(example);
        if (null != list && !list.isEmpty()) {
            return new LuckData(ErrorCode.LUCK_HAS_EXIST);
        }

        // 扣钱
        int ret = userService.updateUserMoney(user, 0, -price, 0, MONKEY_STATUS_NORMAL, ACTION_LUCK);
        if (ErrorCode.SUCCESS != ret) {
            return new LuckData(ret);
        }

        Item item = luck(nohit);
        if (null == item) {
            logger.info("luck error:{}", user.getId());
            return new LuckData(ErrorCode.LUCK_ERROR);
        }

        int r = (int) (Math.random() * item.getRange());
        int generation = item.getGeneration();
        int uuid1 = item.getParam1(r);
        int uuid2 = item.getParam2(r);
        MonkeyCreate create = monkeyService.createData();
        MonkeySpecify specify = new MonkeySpecify(0, 0, 0, 0, uuid2);
        Monkey monkey = monkeyService.create(generation, 0, 0, user, MONKEY_FROM_LUCK, uuid1, create, specify);
        if (null == monkey) {
            logger.info("luck monkey error:{}", user.getId());
        }

        //

        TMonkeyCreate create1 = new TMonkeyCreate();
        create1.setMonkeyid(monkey.getId());
        create1.setUuid(create.getUuid());
        create1.setCreatetime(now);
        if (0 == monkeyCreateMapper.insert(create1)) {
            logger.info("monkey create db error:{}, {}", monkey.getId(), create.getUuid());
        }

        //
        TUserLuck luck = new TUserLuck();
        luck.setUserid(user.getId());
        luck.setPrice(price);
        luck.setData1(generation);
        luck.setData2(uuid1);
        luck.setData3(uuid2);
        luck.setCreatetime(dateString);
        if (0 == userLuckMapper.insert(luck)) {
            logger.info("luck insert error:{}, {}", user.getId());
        }

        return new LuckData(ErrorCode.SUCCESS, monkey.getId(), generation);
    }

    private Item luck(int nohit) {
        if (range <= 0 || null == items || items.isEmpty()) {
            return null;
        }
        int n = (int) (Math.random() * range);
        for (Item item : items) {
            if (item.getStart() <= n && n <= item.getEnd()) {
                return item;
            }
        }
        return items.get(nohit);
    }

    public class Item {
        private int start;
        private int end;
        private int generation;
        private List<Integer> param1 = new ArrayList<>();
        private List<Integer> param2 = new ArrayList<>();

        public Item(int start, int end, int generation, List<Integer> p1, List<Integer> p2) {
            this.start = start;
            this.end = end;
            this.generation = generation;
            this.param1.addAll(p1);
            this.param2.addAll(p2);
        }

        public int getStart() {
            return start;
        }

        public int getEnd() {
            return end;
        }

        public int getGeneration() {
            return generation;
        }

        public int getRange() {
            return param1.size();
        }

        public int getParam1(int i) {
            return param1.get(i);
        }

        public int getParam2(int i) {
            return param2.get(i);
        }
    }
}
